#include "driver/spi_master.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <stdio.h>
#include <string.h>

spi_device_handle_t spi;
spi_transaction_t t;

void spi_init(void)
{
	esp_err_t ret;
	spi_bus_config_t buscfg = {
		.miso_io_num = 2,
		.mosi_io_num = 7,
		.sclk_io_num = 6,
		.quadwp_io_num = -1,
		.quadhd_io_num = -1,
		.max_transfer_sz = 16,
	};

	spi_device_interface_config_t devcfg = {
		.clock_speed_hz = 2400000, // Clock out at 2.4 MHz
		.mode = 0,                 // SPI mode 0
		.spics_io_num = 10,        // CS pin
		.queue_size = 7,           // We want to be able to queue 7 transactions at a time
	};

	ret = spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO);
	ESP_ERROR_CHECK(ret);

	ret = spi_bus_add_device(SPI2_HOST, &devcfg, &spi);
	ESP_ERROR_CHECK(ret);
}

void rgb2mosi(uint32_t rgb, uint8_t* mosi)
{
	int i = 0;     // 循环变量
	uint8_t r = 0; // 存放 R 分量
	uint8_t g = 0; // 存放 G 分量
	uint8_t b = 0; // 存放 B 分量
	uint8_t tmp_color = 0;
	uint32_t tmp_data = 0;
	r = (rgb & 0xff0000) >> 16;
	g = (rgb & 0x00ff00) >> 8;
	b = (rgb & 0x0000ff);

	/* 按照 GRB 的顺序发，且先发高位 */

	/* 构造 spi mosi 输出数据数组，spi 也是 MSB 先发送 */

	/* 当前 bit 是 0, 则转化为 0b100, 0x4 */
	/* 当前 bit 是 1, 则转化为 0b110, 0x6 */

	/* G */
	tmp_color = g;
	tmp_data = 0;
	for (i = 0; i < 8; i++) {
		if ((tmp_color >> i) & 0x1) {
			tmp_data |= 0x6 << (3 * i);
		} else {
			tmp_data |= 0x4 << (3 * i);
		}
	}
	mosi[0] = (tmp_data & 0xff0000) >> 16;
	mosi[1] = (tmp_data & 0x00ff00) >> 8;
	mosi[2] = (tmp_data & 0x0000ff);

	/* R */
	tmp_color = r;
	tmp_data = 0;
	for (i = 0; i < 8; i++) {
		if ((tmp_color >> i) & 0x1) {
			tmp_data |= 0x6 << (3 * i);
		} else {
			tmp_data |= 0x4 << (3 * i);
		}
	}
	mosi[3] = (tmp_data & 0xff0000) >> 16;
	mosi[4] = (tmp_data & 0x00ff00) >> 8;
	mosi[5] = (tmp_data & 0x0000ff);

	/* B */
	tmp_color = b;
	tmp_data = 0;
	for (i = 0; i < 8; i++) {
		if ((tmp_color >> i) & 0x1) {
			tmp_data |= 0x6 << (3 * i);
		} else {
			tmp_data |= 0x4 << (3 * i);
		}
	}
	mosi[6] = (tmp_data & 0xff0000) >> 16;
	mosi[7] = (tmp_data & 0x00ff00) >> 8;
	mosi[8] = (tmp_data & 0x0000ff);
}

void app_main(void)
{
	esp_err_t ret;
	uint32_t rgb = 0xff0000;
	uint8_t data[9] = { 0 };

	rgb2mosi(rgb, data);

	spi_init();

	memset(&t, 0, sizeof(t)); // Zero out the transaction
	t.length = 8 * 9;         // Command is 8 bits
	t.tx_buffer = &data;      // The data is the cmd itself

	while (1) {
		ret = spi_device_polling_transmit(spi, &t); // Transmit!
		ESP_ERROR_CHECK(ret);

		vTaskDelay(200 / portTICK_PERIOD_MS);
	}
}
